package main;

import ai.MiniMax;
import ai.Node;
import checkers.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import javafx.application.Application;
import javafx.stage.Stage;

public class Main extends Application implements Observer {

    private CheckersProblem checkersProblem;
    private CheckersGUI checkersGUI;
    private int smartnessLevel;

    public Main() {
        smartnessLevel = 2;        
        checkersGUI = new CheckersJavaFXGUI();
        checkersGUI.setTopAISmartnessLevel(smartnessLevel);
        //checkersGUI = new CheckersConsoleGUI();
        checkersGUI.addObserver(this);
        startNewGame();
    }

    public static void main(String[] args) {
        launch(args);
    }

    private void startNewGame() {
        checkersProblem = new CheckersProblem();
        checkersGUI.showBoard(checkersProblem.getCurrentState().clone());
        continueMatch(null);
    }

    @Override
    public void update(Observable observable, final Object arg) {
        if (observable == checkersGUI) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    byte argument = (byte) arg;
                    switch (argument) {
                        case CheckersGUI.NOTIFY_USER_HAS_CHOOSED_MOVEMENT:
                            continueMatch(checkersGUI.getLastUserChosenMovement());
                            break;
                        case CheckersGUI.NOTIFY_NEW_GAME:
                            startNewGame();
                            break;
                        case CheckersGUI.NOTIFY_SMARTNESS_LEVEL_CHANGED:
                            smartnessLevel = checkersGUI.getTopAISmartnessLevel();
                            break;
                    }
                }
            });
            thread.start();
        }
    }

    private void continueMatch(CheckersMovement chosenMovement) {
        checkersProblem.getCurrentState().applyMovement(chosenMovement);
        List<CheckersMovement> availableMovements = checkersProblem.availableMovements();
        if (availableMovements != null && !availableMovements.isEmpty()) {
            switch (checkersProblem.getCurrentState().getCurrentPlayer()) {
                case CheckersState.WHITE_PLAYER:
                    userPlays(availableMovements);
                    //aiPlays(availableMovements);                    
                    break;
                case CheckersState.BLACK_PLAYER:
                    //userPlays(availableMovements);
                    aiPlays(availableMovements);
                    break;
            }
        } else {
            matchEnded();
        }
    }

    private void userPlays(List<CheckersMovement> availableMovements) {
        checkersGUI.requestUserMovement(availableMovements);
    }

    private void printMovements(CheckersProblem checkersProblem) {
        for (CheckersMovement m : checkersProblem.availableMovements()) {
            for (CheckersOperation o : m.getMovementsList()) {
                System.out.print((char) ('A' + o.x));
                System.out.print((o.y + 1) + " ");
                switch (o.operation) {
                    case CheckersOperation.BECOME_KING:
                        System.out.print("BECOME_KING");
                        break;
                    case CheckersOperation.REMOVE_PIECE:
                        System.out.print("REMOVE_PIECE");
                        break;
                    case CheckersOperation.SOURCE_POSITION:
                        System.out.print("SOURCE_POSITION");
                        break;
                    case CheckersOperation.TARGET_POSITION:
                        System.out.print("TARGET_POSITION");
                        break;
                }
                System.out.println();
            }
            System.out.println();
        }
    }

    private void aiPlays(List<CheckersMovement> availableMovements) {



        /*if (checkersProblem.getCurrentState().getPlayer() == CheckersState.WHITE_PLAYER) {
         smartnessLevel = 11;
         } else {
         smartnessLevel = 10;
         }*/

        CheckersMovement bestMovement = null;
        List<CheckersMovement> bestMovements = new ArrayList<CheckersMovement>();

        if (availableMovements != null && availableMovements.size() == 1) {
            bestMovement = availableMovements.get(0);
        } else {
            checkersGUI.showAIProcessing(true);
            MiniMax miniMax = new MiniMax(checkersProblem, checkersProblem.getCurrentState().getCurrentPlayer(), smartnessLevel);
            float bestValue = -1000;
            for (CheckersMovement movement : availableMovements) {
                CheckersState state = checkersProblem.getCurrentState().clone();
                state.applyMovement(movement);
                Node node = new Node(1, state);
                node.setUtilityValue(miniMax.minValue(node, -1000, +1000));
                //System.out.println(node.getUtilityValue());
                if (bestMovements.isEmpty()
                        || bestValue < node.getUtilityValue()) {
                    bestMovements.clear();
                    bestMovements.add(movement);
                    bestValue = node.getUtilityValue();
                } else {
                    if (bestValue == node.getUtilityValue()) {
                        bestMovements.add(movement);
                    }
                }
            }
            //System.out.println();
            bestMovement = bestMovements.get(new Random().nextInt(bestMovements.size()));
            checkersGUI.showAIProcessing(false);
        }



        //checkersProblem.getCurrentState().applyMovement(bestMovement);
        checkersGUI.showMovement(bestMovement);



        continueMatch(bestMovement);
        //aiPlays();


    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        //nothing
    }

    private void matchEnded() {
        byte playerWhoWon = (checkersProblem.getCurrentState().getPlayer() == CheckersState.BLACK_PLAYER) ? CheckersState.WHITE_PLAYER : CheckersState.BLACK_PLAYER;
        checkersGUI.showGameEndedMessage(playerWhoWon);
    }
}
